#include "qae_qeditorwindow.h"
#include "qae_qansipalette.h"
#include "qae_qansiwidget.h"
#include "qae_qcolorwidget.h"
#include "qae_qcharwidget.h"
#include "forms/qae_qsettingsdialog.h"
#include "qoptionfiledialog.h"
#include <QtCore/QByteArray>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QDockWidget>
#include <QtGui/QFileDialog>
#include <QtGui/QMenuBar>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QToolBar>


namespace QAnsiEditor {


QEditorWindow::QEditorWindow(QWidget * parent, Qt::WFlags wflags)
        : QMainWindow(parent, wflags)
{
    setMouseTracking(true);
    setWindowIcon(QIcon(":/appicon.png"));
    setWindowTitle("QAnsiEditor");

    m_pAnsiWidget = new QAnsiWidget(this, 24, 80);
    setFocusProxy(m_pAnsiWidget);
    setCentralWidget(m_pAnsiWidget);
    m_pAnsiWidget->setFocus();

    createAction();
    createMenu();
    createToolBar();
    createStatusBar();
    createColorDock();
    createCharDock();
}

QEditorWindow::~QEditorWindow()
{
    delete m_pAnsiWidget;
}

void QEditorWindow::createAction()
{
    newAct = new QAction(QIcon(":/icons/new.png"), tr("&New"), this);
    newAct->setShortcut(tr("Ctrl+N"));
    //newAct->setStatusTip(tr("Create a new file"));
    connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

    openAct = new QAction(QIcon(":/icons/open.png"), tr("&Open..."), this);
    openAct->setShortcut(tr("Ctrl+O"));
    //openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    saveAct = new QAction(QIcon(":/icons/save.png"), tr("&Save"), this);
    saveAct->setShortcut(tr("Ctrl+S"));
    //saveAct->setStatusTip(tr("Save the document to disk"));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));

    exitAct = new QAction(tr("E&xit"), this);
    exitAct->setShortcut(tr("Ctrl+Q"));
    //exitAct->setStatusTip(tr("Exit the application"));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

    undoAct = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this);
    undoAct->setShortcut(tr("Ctrl+Z"));
    //undoAct->setStatusTip(tr("Undo the last operation"));
    connect(undoAct, SIGNAL(triggered()), this, SLOT(undo()));

    redoAct = new QAction(QIcon(":/icons/redo.png"), tr("&Redo"), this);
    redoAct->setShortcut(tr("Ctrl+Y"));
    //redoAct->setStatusTip(tr("Redo the last operation"));
    connect(redoAct, SIGNAL(triggered()), this, SLOT(redo()));

    cutAct = new QAction(QIcon(":/icons/cut.png"), tr("Cu&t"), this);
    cutAct->setShortcut(tr("Ctrl+X"));
    //cutAct->setStatusTip(tr("Cut the current selection's contents to the "
    //                        "clipboard"));
    connect(cutAct, SIGNAL(triggered()), this, SLOT(cut()));

    copyAct = new QAction(QIcon(":/icons/copy.png"), tr("&Copy"), this);
    copyAct->setShortcut(tr("Ctrl+C"));
    //copyAct->setStatusTip(tr("Copy the current selection's contents to the "
    //                         "clipboard"));
    connect(copyAct, SIGNAL(triggered()), this, SLOT(copy()));

    pasteAct = new QAction(QIcon(":/icons/paste.png"), tr("&Paste"), this);
    pasteAct->setShortcut(tr("Ctrl+V"));
    //pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
    //                          "selection"));
    connect(pasteAct, SIGNAL(triggered()), this, SLOT(paste()));

    settingsAct = new QAction(QIcon(":/icons/settings.png"), tr("&Settings"), this);
    connect(settingsAct, SIGNAL(triggered()), this, SLOT(settings()));

    aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void QEditorWindow::newFile()
{
    getAnsiWidget()->newFile();
}

void QEditorWindow::open()
{
    QOptionFileDialog fileDialog(this, tr("Open"), QDir::currentPath());
    QStringList filterList;
    filterList << QString(tr("ANSI Files (*.%1)")).arg(QGlobal::FILE_SIGN);
    filterList << tr("All Files (*)");
    fileDialog.setFilters(filterList);
    QLabel *lbEncoding = new QLabel(tr("Encoding:"));
    QComboBox *cbEncoding = new QComboBox;
    cbEncoding->addItem("GBK", QGlobal::GBK);
    cbEncoding->addItem("Big5", QGlobal::Big5);
    cbEncoding->addItem("UTF-8", QGlobal::UTF8);
    cbEncoding->setCurrentIndex(QGlobal::instance()->inputEncoding());
    fileDialog.addOption(lbEncoding, cbEncoding);
    if (fileDialog.exec() == QDialog::Accepted) {
        QString fileName = fileDialog.selectedFiles().value(0);
        if (fileName != "") {
            QFile file(fileName);
            if (!file.open(QIODevice::ReadOnly)) {
                return;
            }
            QByteArray arrRawData = file.readAll();
            int iSign = QString(QGlobal::FILE_SIGN).length();
            int iLength = 3 + iSign + 2;
            bool isOurFormat = false;
            if (arrRawData.length() < 3) {
                isOurFormat = false;
            } else {
                if (arrRawData[0] != (char)0xef
                    || arrRawData[1] != (char)0xbb
                    || arrRawData[2] != (char)0xbf) {
                    isOurFormat = false;
                } else {
                    QString s = QString(arrRawData.mid(3, iSign));
                    if ((arrRawData.length()<iLength)
                        || ( (arrRawData.length()>=iLength) && (QString(arrRawData.mid(3, iSign)) != QGlobal::FILE_SIGN)) ) {
                            QMessageBox::critical(this, "Error", "File format not supported!");
                            return;
                    } else {
                        isOurFormat = true;
                    }
                }
            }
            // parse
            if (isOurFormat) {
                QByteArray arrContent = arrRawData.mid(iLength);
                getAnsiWidget()->setContent(arrContent, QGlobal::UTF8);
            } else {
                int iIndex = cbEncoding->currentIndex();
                getAnsiWidget()->setContent(arrRawData, (QGlobal::Encoding)cbEncoding->itemData(iIndex).toInt());
            }
        }
    }
}

void QEditorWindow::save()
{
    QOptionFileDialog fileDialog(this,
        tr("Open"), QDir::currentPath(), QString(tr("ANSI Files (*.%1)")).arg(QGlobal::FILE_SIGN));
    if (fileDialog.exec() == QDialog::Accepted) {
        QString fileName = fileDialog.selectedFiles().value(0);
        if (fileName != "") {
            QByteArray arrContent = getAnsiWidget()->getContent(QGlobal::UTF8);
            if (fileName.endsWith(QGlobal::FILE_SIGN)) {
                fileName = fileName + "." + QGlobal::FILE_SIGN;
            }
            QFile file(fileName);
            if (!file.open(QIODevice::WriteOnly)) {
                return;
            }
            QDataStream out(&file);
            // Add UTF-8 BOM
            char bom[] = { (char)0xef, (char)0xbb, (char)0xbf };
            out.writeRawData(bom, 3);
            // Add file signature and content
            out.writeRawData(QGlobal::FILE_SIGN, QString(QGlobal::FILE_SIGN).length());
            out.writeRawData("\r\n", 2);
            out.writeRawData(arrContent, arrContent.length());
        }
    }
}

void QEditorWindow::undo()
{
    getAnsiWidget()->undo();
}

void QEditorWindow::redo()
{
    getAnsiWidget()->redo();
}

void QEditorWindow::cut()
{
    getAnsiWidget()->cut();
}

void QEditorWindow::copy()
{
    getAnsiWidget()->copy();
}

void QEditorWindow::paste()
{
    getAnsiWidget()->paste();
}

void QEditorWindow::settings()
{
    QSettingsDialog settingDialog(this);
    settingDialog.exec();
}

void QEditorWindow::about()
{
    QMessageBox::about(this, "About",
        QString("%1 v%2%4%3%4").arg(QAE_APP_NAME, QAE_VERSION, "(C) 2010 gonwan. This is free software.", QString(QChar::LineSeparator)));
}

void QEditorWindow::createMenu()
{
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(newAct);
    fileMenu->addAction(openAct);
    fileMenu->addAction(saveAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(undoAct);
    editMenu->addAction(redoAct);
    editMenu->addSeparator();
    editMenu->addAction(cutAct);
    editMenu->addAction(copyAct);
    editMenu->addAction(pasteAct);
    editMenu->addSeparator();

    viewMenu = menuBar()->addMenu(tr("&View"));

    toolsMenu = menuBar()->addMenu(tr("&Tools"));
    toolsMenu->addAction(settingsAct);

    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);

}

void QEditorWindow::createToolBar()
{
    fileToolBar = addToolBar(tr("File"));
    fileToolBar->addAction(newAct);
    fileToolBar->addAction(openAct);
    fileToolBar->addAction(saveAct);

    editToolBar = addToolBar(tr("Edit"));
    editToolBar->addAction(undoAct);
    editToolBar->addAction(redoAct);
    editToolBar->addAction(cutAct);
    editToolBar->addAction(copyAct);
    editToolBar->addAction(pasteAct);
}

void QEditorWindow::createStatusBar()
{
    statusBar()->showMessage("Ready!");
}

void QEditorWindow::createColorDock()
{
    // widget
    m_pColorWidget = new QColorWidget(this);
    connect(m_pColorWidget, SIGNAL(colorChanged(char)), m_pAnsiWidget, SLOT(colorChanged(char)));
    connect(m_pColorWidget, SIGNAL(blinkToggled(bool)), m_pAnsiWidget, SLOT(blinkToggled(bool)));
    connect(m_pColorWidget, SIGNAL(underlineToggled(bool)), m_pAnsiWidget, SLOT(underlineToggled(bool)));
    // dock
    QDockWidget *colorDock = new QDockWidget(tr("Color"), this);
    colorDock->setAllowedAreas(Qt::RightDockWidgetArea);
    colorDock->setWidget(m_pColorWidget);
    addDockWidget(Qt::RightDockWidgetArea, colorDock);
    viewMenu->addAction(colorDock->toggleViewAction());
}

void QEditorWindow::createCharDock()
{
    // widget
    m_pCharWidget = new QCharWidget(this);
    connect(m_pCharWidget, SIGNAL(charClicked(QTableWidgetItem *)), m_pAnsiWidget, SLOT(charClicked(QTableWidgetItem *)));
    // dock
    QDockWidget *charDock = new QDockWidget(tr("Tools"), this);
    charDock->setAllowedAreas(Qt::RightDockWidgetArea);
    charDock->setWidget(m_pCharWidget);
    addDockWidget(Qt::RightDockWidgetArea, charDock);
    viewMenu->addAction(charDock->toggleViewAction());
}


}  // namespace QAnsiEditor
